package ui;
import infrastructure.exceptions.PrivilidgesException;
import infrastructure.exceptions.operations.OperationException;
import inftrastructure.exceptions.ClientRuntimeException;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.Insets;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.Vector;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.filechooser.FileFilter;

import dal.Pet;
import dal.Pet_type;


public class AddPetDialog extends JDialog implements ActionListener {

	// Data Members Definition
	private final int PICTURE_HEIGHT = 120;
	private final int PICTURE_WIDTH = 120;
	private ClientFrame parentFrame = null;
	private AddPetDialog thisDialog = null;
	private String petName = null;
	private Pet deliveredPet = null ;
	private String shortDesc = null;
	private String longDesc = null;
	private Pet_type petType = null;
	private String deliveredUser = null;
	private Iterator<Pet_type> petsTypeIter = null;
	private Vector<Pet_type> petTypeVec = null;
	private File pictureFile = null;
	private ImageIcon petImage = null;
	private byte[] picture = null;
	private BufferedImage bufferedImg = null;
	
	// Components Definition
	private JFileChooser fileChooser = new JFileChooser();
	private JPanel picturePane = new JPanel(); 
	private JPanel dialogPanel = new JPanel(new GridBagLayout());
	private JPanel buttonsPanel = new JPanel(new FlowLayout());
	private JComboBox petTypeComboBox = null;
	private JTextField petNameField = new JTextField(15);
	private JTextField deliverUserField = new JTextField(10);
	private JTextField shortDescField = new JTextField(10);
	private JTextArea LongDesctextArea = new JTextArea(10,30);
	private JLabel petNameLabel = new JLabel ("Pet's Name:");
	private JLabel petTypeLabel = new JLabel ("Pet's Type:");
	private JLabel deliverUserLabel = new JLabel ("Delivered By:");
	private JLabel shortDescLabel = new JLabel ("Short Description:");
	private JLabel longDescLabel = new JLabel ("Long Description:");
	private JScrollPane longDescScrollPane = new JScrollPane(LongDesctextArea);
	private JButton okButton = new JButton ("OK");
	private JButton cancelButton = new JButton ("Cancel");
	private JButton pictureButton = new JButton ("Upload pet's picture");

	private JLabel[] labels = {deliverUserLabel, petNameLabel, petTypeLabel, shortDescLabel, longDescLabel};
	private JTextField[] textFields = {deliverUserField, petNameField,  shortDescField};
	
	
	// Constructor Definition
	public AddPetDialog (ClientFrame parentframe, String title)
	{
		// Set the title
		super(parentframe, title);
			
		// Set reference to parent frame
		parentFrame = parentframe;
		
		// Set reference to this dialog frame
		thisDialog = this;
		
		// Initialize pet's type CmboBox
		petTypeComboBox = new JComboBox();
		petTypeComboBox.setFont(new Font("DialogInput", Font.PLAIN, 12));
		petTypeComboBox.setEditable(false);
		deliverUserField.setEditable(false);
		
		// Format fields and labels
		petNameField.setFont(new Font("DialogInput", Font.PLAIN, 12));
		petTypeComboBox.setFont(new Font("DialogInput", Font.PLAIN, 12));
		shortDescField.setFont(new Font("DialogInput", Font.PLAIN, 12));
		LongDesctextArea.setFont(new Font("DialogInput", Font.PLAIN, 12));
		petNameLabel.setFont(new Font("Dialog", Font.PLAIN, 12));
		petTypeLabel.setFont(new Font("Dialog", Font.PLAIN, 12));
		deliverUserLabel.setFont(new Font("Dialog", Font.PLAIN, 12));
		shortDescLabel.setFont(new Font("Dialog", Font.PLAIN, 12));
		longDescLabel.setFont(new Font("Dialog", Font.PLAIN, 12));
		petNameLabel.setLabelFor(petNameField);
		petTypeLabel.setLabelFor(petTypeComboBox);
		deliverUserLabel.setLabelFor(deliverUserField);
		shortDescLabel.setLabelFor(shortDescField);
		longDescLabel.setLabelFor(LongDesctextArea);
		
		picturePane.setSize(PICTURE_WIDTH, PICTURE_HEIGHT);
		
		longDescScrollPane.setVerticalScrollBarPolicy(
                JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
		
		// Set button tooltip
		pictureButton.setToolTipText("Select pet's picture to upload");

		// Initialize delivered user text field with the current logged-in Username
		deliveredUser = parentFrame.currUser.getUsername();
		deliverUserField.setText(deliveredUser);
		
		// add components to container
		addtextRows(labels, textFields, 
				dialogPanel);
		picturePane.add(pictureButton, BorderLayout.CENTER);
		buttonsPanel.add(okButton);
		buttonsPanel.add(cancelButton);
		getContentPane().add(dialogPanel, BorderLayout.CENTER);
		getContentPane().add(buttonsPanel, BorderLayout.SOUTH);
		
		// Register Avtion Listeners
		okButton.addActionListener(this);
		cancelButton.addActionListener(this);
		pictureButton.addActionListener(this);
		
		// Initialize the ComboBox and display the Windows
		setModal(true); 
		setSize(400,400);
		setResizable(false);
		setDefaultCloseOperation(DISPOSE_ON_CLOSE);
		initPetTypeCombo();
		pack();
		setLocationRelativeTo(null);
		setVisible(true);
	}
	
	public void actionPerformed(ActionEvent e) {
		
		if (e.getSource() == okButton)
		{
			// Check for pet types
			if (petTypeComboBox.getSelectedItem() == null || petTypeComboBox.getSelectedIndex() == -1)
			{
				// if the PetType table in DB is empty then return
				JOptionPane.showMessageDialog(null, "Ask your administrator to add pet types to the repository",
						"No pet type found in repository", JOptionPane.ERROR_MESSAGE);
				dispose();
			}
			// Check if the user entered pet's name
			if (petNameField.getText() == null || petNameField.getText().equals(""))
			{
				JOptionPane.showMessageDialog(null, "You must enter pet's name",
						"Warning", JOptionPane.WARNING_MESSAGE);
			}
			// Check if the user entered pet's short description
			else if (shortDescField.getText() == null || shortDescField.getText().equals(""))
			{
				JOptionPane.showMessageDialog(null, "You must enter pet's short description",
						"Warning", JOptionPane.WARNING_MESSAGE);
			}
			else
			{
				// Get the petType index from the ComboBox and select the petType from vector
				petName = petNameField.getText();
				shortDesc = shortDescField.getText();
				petType = petTypeVec.get(petTypeComboBox.getSelectedIndex());
				
				// If an image were selected by the user convert it into bytes array
				if (petImage != null)
				{
					ByteArrayOutputStream bytearrayoutputstream = new ByteArrayOutputStream();
					try 
					{
						// Create a scaled BufferedImage object from the pet's image
						bufferedImg = getScaledBufferedImage(petImage.getImage());
						
						// Writing the scaled buffered image into byte array output stream
						ImageIO.write(bufferedImg, Utils.getExtension(pictureFile), bytearrayoutputstream);
						picture = bytearrayoutputstream.toByteArray();	
					} 
					catch (IOException e1)
					{
						JOptionPane.showMessageDialog(null, "Error converting image into byteArray.\nImage will not be uploaded",
								"ERROR", JOptionPane.ERROR);
						e1.printStackTrace();
						picture = null;
					}
				}
	
				if (LongDesctextArea.getText() != null)
				{
					longDesc = LongDesctextArea.getText();
					
				}
				
				deliveredPet = new Pet(petType, petName, shortDesc, longDesc,picture);
				
				try
				{
					// Register pet to adoption using the based on session information
					parentFrame.currClient.session.giveForAdoption(deliveredPet);
				}
				catch (OperationException ex)
				{
					JOptionPane.showMessageDialog(null, "Giving pet for adoption failed on the server\n" +
							"Call your system administrator",
							"Error", JOptionPane.ERROR_MESSAGE);
					dispose();
				}
				catch (PrivilidgesException ex)
				{
					JOptionPane.showMessageDialog(null, "No sufficient privileges to preform operation!\n" +
							"Call your system administrator",
							"Error", JOptionPane.ERROR_MESSAGE);
					dispose();
				}
				catch (Exception ex)
				{
					throw new ClientRuntimeException(ex.getMessage(), ex);
				}
				
				// Close the dialog
				dispose();	
			}
		}
		else if (e.getSource() == cancelButton)
		{
			// Close the dialog
			dispose();	
		}
		else if (e.getSource() == pictureButton)
		{
			int returnVal;
						
		    //Add a custom file filter and disable the default(Accept All)
				// file filter.
				fileChooser.addChoosableFileFilter(new ImageFilter());
				fileChooser.setAcceptAllFileFilterUsed(false);

	        //Show FIleChooser dialog.
	        returnVal = fileChooser.showDialog(thisDialog,
	                                      "Open");
	        //Process the results.
	        if (returnVal == JFileChooser.APPROVE_OPTION)
	        {
	        	pictureFile = fileChooser.getSelectedFile();
	        	
				System.out.println("Debug - file choosen is " + pictureFile.getPath());
				
				try 
				{
					bufferedImg = ImageIO.read(pictureFile);
				} catch (IOException e1)
				{
					JOptionPane.showMessageDialog(null, "Error reading picture file",
							"Error", JOptionPane.ERROR_MESSAGE);
					e1.printStackTrace();
					return;
				}
				petImage = new ImageIcon(bufferedImg);

				// ReScale the new Image
				petImage =  getScaledImage(petImage.getImage(), PICTURE_WIDTH, PICTURE_HEIGHT);

				// Display the image on the button
	        	pictureButton.setIcon(petImage);
	        	pictureButton.setText(null);
	        	pictureButton.setMargin(new Insets(0,0,0,0));
	    		pictureButton.setSize(petImage.getIconWidth(), petImage.getIconHeight());
	        }
	        
	        //Reset the file chooser for the next time it's shown.
	        fileChooser.setSelectedFile(null);
		}
	}

	private ImageIcon getScaledImage(Image srcImg, int w, int h)
	{
		/** This method receive an image and resize it to desirable size. It useds a bufferedImage object to
		 * produce GraphicsG2 object to scale the image*/
		
        BufferedImage resizedImg = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2 = resizedImg.createGraphics();
        g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g2.drawImage(srcImg, 0, 0, w, h, null);
        g2.dispose();
        return new ImageIcon(resizedImg);
    }
	
	private BufferedImage getScaledBufferedImage(Image srcImg)
	{
		/** This method receive an already scaled image and produce, using Graphics2d object,
		 *  a matching BufferedImage to the received image*/
		
		BufferedImage bugImg = new BufferedImage(PICTURE_WIDTH, PICTURE_HEIGHT, BufferedImage.TYPE_INT_RGB);
		Graphics2D bufImageGraphics = bugImg.createGraphics();
		bufImageGraphics.drawImage(srcImg, 0, 0, null);
		bufImageGraphics.dispose();
        return bugImg;
    }
	
	private void initPetTypeCombo ()
	{
		int index;
		try
		{
			// Get pets types iterator from the client parent frame
			petsTypeIter = parentFrame.currClient.session.getAllPetTypes();
			petTypeVec = new Vector<Pet_type>();
			index = 0;
			
			while (petsTypeIter.hasNext())
			{
				petTypeVec.add(petsTypeIter.next());
				
				// Initialize ComboBox with the pet types at the same index as in the Vector
				petTypeComboBox.insertItemAt((petTypeVec.get(index)).getType_name(), index);
				index++;
			}
			
			// Check that pets list is not empty
			if (petTypeVec.size() > 0)
			{
				petTypeComboBox.setSelectedIndex(0);
			}
			else
			{
				petTypeComboBox.setSelectedIndex(-1);
			}
		}
		catch (PrivilidgesException ex)
		{
			JOptionPane.showMessageDialog(null, "No sufficient privileges to preform operation!\n" +
					"Call your system administrator",
					"Error", JOptionPane.ERROR_MESSAGE);
			throw new ClientRuntimeException(ex.getMessage(), ex);
		}
		catch(Exception ex)
		{
			throw new ClientRuntimeException(ex.getMessage(), ex);
		}		
	}
	
	private void addtextRows(JLabel[] labels, JTextField[] textfields, 
			Container container)
	{
		int index = 0;
		Insets insets = new Insets(4,2,2,2);
		GridBagConstraints labelsConstrains = new GridBagConstraints();
		GridBagConstraints textfieldsConstrains = new GridBagConstraints();
		GridBagConstraints textareaConstrains = new GridBagConstraints();
		GridBagConstraints pictureConstrains = new GridBagConstraints();
		
		// set constraints for labels
		labelsConstrains.gridx = 0; // labels at the left column
		labelsConstrains.gridy = 0;
		labelsConstrains.anchor = GridBagConstraints.FIRST_LINE_START; // align label to the uperleft
		labelsConstrains.gridwidth = 1; // each label occupies 1 cell
		labelsConstrains.fill = GridBagConstraints.NONE;
		labelsConstrains.weightx = 0.0;
		labelsConstrains.weighty = 0.0;
		labelsConstrains.insets = insets;
		
		// set constraints for text fields
		textfieldsConstrains.gridx = 1; // text fields at the second column 
		textfieldsConstrains.gridy = 0;
		textfieldsConstrains.anchor = GridBagConstraints.FIRST_LINE_START; // align text fields to the left
		textfieldsConstrains.gridwidth = 2; // each text field occupies 2 cells
		textfieldsConstrains.weightx = 1.0;
		textfieldsConstrains.weighty = 0.0;
		textfieldsConstrains.insets = insets;
		textfieldsConstrains.fill = GridBagConstraints.HORIZONTAL;
		
		// set constraints for text area
		textareaConstrains.gridx = 1; // text area at the second column 
		textareaConstrains.anchor = GridBagConstraints.FIRST_LINE_START;; // align text areas to the left
		textareaConstrains.gridwidth = 2; // text area occupies 2 cell
		textareaConstrains.weightx = 1.0;
		textareaConstrains.weighty = 1.0;
		textareaConstrains.insets = insets;
		textareaConstrains.fill = GridBagConstraints.BOTH;
		
		// set constraints for picture pan
		pictureConstrains.gridx = 3; // picture at the fourth column 
		pictureConstrains.gridy = 0; // picture at the first row
		pictureConstrains.anchor = GridBagConstraints.CENTER; // picture areas to the left
		pictureConstrains.gridwidth = 1; // picture occupies 1 row cell 
		pictureConstrains.gridheight = 4; // picture occupies 2 row cell
		pictureConstrains.weightx = 0.0;
		pictureConstrains.weighty = 0.0;
		pictureConstrains.insets = new Insets(1,1,1,1);
		pictureConstrains.fill = GridBagConstraints.BOTH;

		container.add(picturePane, pictureConstrains);
		
		// put delivered user and its label in layout
		container.add(labels[index], labelsConstrains);
		container.add(textfields[index], textfieldsConstrains);
		labelsConstrains.gridy++;
		textfieldsConstrains.gridy++;
		index++;
		
		// put pet's name and its label in layout
		container.add(labels[index], labelsConstrains);
		container.add(textfields[index], textfieldsConstrains);
		labelsConstrains.gridy++;
		textfieldsConstrains.gridy++;
		index++;
		
		// put ComboBox of pet type and its label in layout
		container.add(labels[index], labelsConstrains);
		container.add(petTypeComboBox, textfieldsConstrains);
		labelsConstrains.gridy++;
		textfieldsConstrains.gridy++;
		index++;
		
		// put short desc and its label in layout
		container.add(labels[index], labelsConstrains);
		container.add(textfields[index - 1], textfieldsConstrains);
		labelsConstrains.gridy++;
		textfieldsConstrains.gridy++;
		index++;
		
		// put long desc and their labels in layout
		textareaConstrains.gridy = textfieldsConstrains.gridy; // text area will be at the last row
		container.add(labels[index], labelsConstrains);
		container.add(longDescScrollPane, textareaConstrains);
	}

	private class ImageFilter extends FileFilter
	{

	    /** Accept only directory files and all gif, jpg or png files. */
	    public boolean accept(File f)
	    {
	        if (f.isDirectory())
	        {
	        	// Accept directory files
	            return true;
	        }

	        String extension = Utils.getExtension(f);
	        if (extension != null) {
	            if (extension.equals(Utils.gif) ||
	                extension.equals(Utils.jpeg) ||
	                extension.equals(Utils.jpg) ||
	                extension.equals(Utils.png)) {
	                    return true;
	            } else {
	                return false;
	            }
	        }
	        return false;
	    }
	    //The description of this filter
	    public String getDescription()
	    {
	        return "Just Images";
	    }
	}

	protected static class Utils
	{
	    public final static String jpeg = "jpeg";
	    public final static String jpg = "jpg";
	    public final static String gif = "gif";
	    public final static String tiff = "tiff";
	    public final static String tif = "tif";
	    public final static String png = "png";

	    /** Get the extension of a file. */
	    
	    public static String getExtension(File f) {
	        String ext = null;
	        String s = f.getName();
	        int i = s.lastIndexOf('.');

	        if (i > 0 &&  i < s.length() - 1) {
	            ext = s.substring(i+1).toLowerCase();
	        }
	        return ext;
	    }
	}
}
